// etcd选主 demo
// rpc使用现成的grpc了，分布式也使用现成的吧，自己写的不可靠。以后有机会自己写，先把这个设想框架实现出来看看。后面在其它项目上尝试自己实现
// 分布式使用etcd go get go.etcd.io/etcd/client && go get go.etcd.io/etcd/clientv3 实际上这是错误的要go get go.etcd.io/etcd/client/v3才有效
package demo

import (
	"context"
	"fmt"
	"time"

	etcdclient "go.etcd.io/etcd/client/v3"
	etcdelection "go.etcd.io/etcd/client/v3/concurrency"
)

func init() {
	Register("EtcdElection", func() Service {
		return new(EtcdElection)
	})

	fmt.Println("EtcdElection registered")
}

type EtcdElection struct{}

func (ee *EtcdElection) Exec() {
	client, err := etcdclient.New(etcdclient.Config{
		Endpoints:   []string{"http://localhost:2379"},
		DialTimeout: 5 * time.Second,
	})

	if err != nil {
		fmt.Printf("failed to etcd_election: %v\n", err)
		return
	}
	defer client.Close()

	// 创建一个会话
	session, err := etcdelection.NewSession(client)
	if err != nil {
		fmt.Printf("failed to etcd_election session: %v\n", err)
	}
	defer session.Close()

	// 创建一个选举对象
	election := etcdelection.NewElection(session, "my-election")

	// 参与选举
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	err = election.Campaign(ctx, "candidate-1")
	if err != nil {
		fmt.Printf("campaign failed: %v\n", err)
		// 处理选举失败的情况，例如重试或退出
	} else {
		fmt.Println("became leader!")

		// 在这里处理作为 leader 的逻辑

		// ...

		// 完成后，可以主动放弃领导地位（可选）
		// 注意：在实际应用中，通常会有一个持续运行的循环或 goroutine 来保持领导地位，
		// 直到发生错误、超时或主动辞职。
		err = election.Resign(context.Background())
		if err != nil {
			fmt.Printf("resign failed: %v\n", err)
		} else {
			fmt.Println("resigned as leader.")
		}
	}
}
